import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;


import javax.swing.*;
import javax.swing.border.EtchedBorder;
import javax.swing.text.AttributeSet;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;


import opendap.dap.Attribute;
import opendap.dap.AttributeTable;
import opendap.dap.BaseType;
import opendap.dap.DAS;
import opendap.dap.DConnect2;
import opendap.dap.DDS;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.awt.SystemColor;


public class ClientWindow {

	private JFrame frame;
	
	JLabel urlLabel = new JLabel("Data URL: ");
	JTextField urlTextBox = new JTextField("", 50);
	JPanel variablesPanel = new JPanel();
	
	JTextField constraintTextBox = new JTextField("", 20);
	JLabel constraintLabel = new JLabel("Constraint Expr: ");
	JButton btnGetData = new JButton("Get Data");
	
	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					ClientWindow window = new ClientWindow();
					window.frame.setVisible(true);
					window.frame.setTitle("OpenDAP Client");
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public ClientWindow() {
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frame = new JFrame();
		frame.setBounds(100, 100, 883, 567);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setMinimumSize(new Dimension(650, 800));
		
		Container contentPane = frame.getContentPane();
		SpringLayout layout = new SpringLayout();
		
//DEBUG line, hard coding url for now so I don't have to keep inputing it
		urlTextBox.setText("http://test.opendap.org/dap/data/nc/sst.mnmean.nc.gz");
		
		
		contentPane.setLayout(layout);
		contentPane.add(urlLabel);
		contentPane.add(urlTextBox);
		
		layout.putConstraint(SpringLayout.WEST, urlLabel,
							 5, 
							 SpringLayout.WEST, contentPane);
		layout.putConstraint(SpringLayout.NORTH, urlLabel,
				 			  5, 
				 			  SpringLayout.NORTH, contentPane);
		
		
		//Adjust constraints for the text field so it's at
		//(<label's right edge> + 5, 5).
		layout.putConstraint(SpringLayout.WEST, urlTextBox,
		                     5,
		                     SpringLayout.EAST, urlLabel);
		layout.putConstraint(SpringLayout.NORTH, urlTextBox,
		                     5,
		                     SpringLayout.NORTH, contentPane);
		
		JButton btnCheckUrl = new JButton("Check URL");
		btnCheckUrl.addActionListener(new btnCheckUrlListener());

		layout.putConstraint(SpringLayout.NORTH, btnCheckUrl, 6, SpringLayout.SOUTH, urlTextBox);
		layout.putConstraint(SpringLayout.EAST, btnCheckUrl, 0, SpringLayout.EAST, urlTextBox);
		frame.getContentPane().add(btnCheckUrl);
				
		layout.putConstraint(SpringLayout.NORTH, variablesPanel, 6, SpringLayout.SOUTH, btnCheckUrl);
		variablesPanel.setBackground(SystemColor.menu);
		layout.putConstraint(SpringLayout.WEST, variablesPanel, 5, SpringLayout.WEST, frame.getContentPane());
		layout.putConstraint(SpringLayout.SOUTH, variablesPanel, 0, SpringLayout.SOUTH, frame.getContentPane());
		layout.putConstraint(SpringLayout.EAST, variablesPanel, 624, SpringLayout.WEST, frame.getContentPane());
		GridLayout variablePanelLayout = new GridLayout(0,1);
		variablePanelLayout.setVgap(5);
		variablesPanel.setLayout(variablePanelLayout);
		frame.getContentPane().add(variablesPanel);
							
		
		frame.pack();
		
		
	}
	
/** Listen for CheckUrl button click events
 * 
 * @author AJ
 * 
 */
    private class btnCheckUrlListener implements ActionListener
    {
    	
		@Override
		public void actionPerformed(ActionEvent evt) 
		{
	    	String url = urlTextBox.getText().trim();
			try{
				DConnect2 dc = new DConnect2(url);
			
				System.out.println("");
		        System.out.println("");
		        System.out.println("########################################################");
		        System.out.println("\nConnecting to " + url + "\n");
		
		

		        System.out.println("\n- - - - - - - - - - - - - - - - - - -");
		
		        System.out.println("Retrieving DDS:\n");
		        DDS dds = dc.getDDS();
		        dds.print(System.out);				

		        //Create a list of variables from dds object
		        List<BaseType> ddsVar = new ArrayList<BaseType>();
		        
		        for(Enumeration e = dds.getVariables(); e.hasMoreElements();)
		        {      	
		        	ddsVar.add((BaseType) e.nextElement());		      		        	
		        }

		        //Get 	        
		        DAS das = dc.getDAS();
		        
		        
		        for(int j = 0; j < ddsVar.size(); j++)
		        {
		        	System.out.println("Element count: " + ddsVar.get(j).elementCount() + " Attribute name: " + ddsVar.get(j).getAttribute().getName() );		        	
		        	//das.getAttribute(ddsVar.get(j).getAttribute().getName()).print(System.out);
		        	Attribute varAttr = 	das.getAttribute(ddsVar.get(j).getAttribute().getName());
		        	if(varAttr.isContainer())
		        	{
		        		AttributeTable attTable = varAttr.getContainer();
		        		Enumeration es = attTable.getNames();
		        		while(es.hasMoreElements())
		        		{
		        			String attrName = (String) es.nextElement();
		        			Attribute innerAttr = attTable.getAttribute(attrName);
		        			System.out.println("Printing attribute name: " + attrName);
		        			Enumeration attValues = innerAttr.getValues();
		        			while(attValues.hasMoreElements())
		        			{
		        				String attValue = (String) attValues.nextElement();
		        				System.out.println("Printing attribute value: " + attValue);
		        			}
		        			
		        		}
		        	}
		        	
		        	//System.out.println(varAttr.getName() + " " + varAttr.getType() + " " + varAttr.getNumVal());
		        	    
		        	
		        
		        }
		        
		        for(int i = 0; i < ddsVar.size(); i++)
		        {
			        
		        	//Create a new panel to hold all the controls associated with one variable, then add that panel to a parent panel later
		        	JPanel varXPanel = new JPanel();  			       
		        	//varXPanel.setBackground(Color.white);
		        	//varXPanel.setBorder(BorderFactory.createLineBorder(Color.red));
		        	varXPanel.setPreferredSize(new Dimension(varXPanel.getWidth(), 100));


		        	//Add dataset information for each variable
			        JLabel varLabel = new JLabel("Variable:");
			        JTextField varText = new JTextField(ddsVar.get(i).getName() , ddsVar.get(i).getName().length());
			        varText.setEditable(false);
			        
			        //Create a text pane to display attribute text
			        JTextPane attrPane = new JTextPane();
			        attrPane.setBackground(variablesPanel.getBackground());
			        attrPane.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
			       	attrPane.setBounds(0, 0, varXPanel.getWidth(), 100);

			       	//Add the textpane as a client of a ScrollPane so we can scroll down if there is more text to display
			        JScrollPane slidePanel = new JScrollPane(attrPane);
			        //slidePanel.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);			        
			        slidePanel.setBounds(0,0, varXPanel.getWidth(), 100);
			        //slidePanel.setBorder(BorderFactory.createLineBorder(Color.blue));			        
			        
			        //Get the document so we can add text to it
			        StyledDocument doc = attrPane.getStyledDocument();
			        	        
			        
			        // Load the default style and add it as the "regular" text
			        Style def = StyleContext.getDefaultStyleContext().getStyle( StyleContext.DEFAULT_STYLE );
			        Style regular = doc.addStyle( "regular", def );	
	
			        // Create a bold style
			        Style bold = doc.addStyle( "bold", regular );
			        StyleConstants.setBold( bold, true );	
	        
			        String msg = "Variable Type: ";
			        doc.insertString(doc.getLength(), msg, bold);
			        doc.insertString(doc.getLength(), ddsVar.get(i).getTypeName() +"\n", regular );
			        
			        //Add information about each attribute
		        	Attribute varAttr = 	das.getAttribute(ddsVar.get(i).getAttribute().getName());
		        	if(varAttr.isContainer())
		        	{
		        		AttributeTable attTable = varAttr.getContainer();
		        		Enumeration es = attTable.getNames();
		        		while(es.hasMoreElements())
		        		{
		        			String attrName = (String) es.nextElement();
		        			Attribute innerAttr = attTable.getAttribute(attrName);
		        			
		        			doc.insertString(doc.getLength(), attrName + ": ", bold);
		        			Enumeration attValues = innerAttr.getValues();
		        			int numValues = innerAttr.getNumVal();
		        			while(attValues.hasMoreElements())
		        			{
		        				String attValue = (String) attValues.nextElement();

		        				if(numValues > 1){
		        					doc.insertString(doc.getLength(), attValue + ", ", regular);
		        				}
		        				else
		        				{
		        					doc.insertString(doc.getLength(), attValue, regular);
		        				}
		        				numValues--;
		        			}
		        			doc.insertString(doc.getLength(),"\n", regular);
		        		}
		        	}			        
			        
		        	//Reset textpane to top of text so scrollbar starts at top
			        attrPane.setCaretPosition(0);
			        
			        SpringLayout layout = new SpringLayout();
			        varXPanel.setLayout(layout);

//			        //Adjust variable label field so its at (x,y):
//			        // 5, 5 (on varXPanel)
			        layout.putConstraint(SpringLayout.NORTH, varLabel, 5, SpringLayout.NORTH, varXPanel);
			        layout.putConstraint(SpringLayout.WEST, varLabel, 5, SpringLayout.WEST, varXPanel);

//			        //Adjust variable name text box so its at (x,y):
//			        // <varLabel + 5>, <varLabel>
			        layout.putConstraint(SpringLayout.NORTH, varText, 0, SpringLayout.NORTH, varLabel);
			        layout.putConstraint(SpringLayout.WEST, varText, 5, SpringLayout.EAST, varLabel);
	        
//			        //Adjust attribute pane so its at (x,y):
//			        // <varLabel> , <varLabel + 7>			        
//			        layout.putConstraint(SpringLayout.NORTH, attrPane, 7, SpringLayout.SOUTH, varLabel);
//			        layout.putConstraint(SpringLayout.WEST, attrPane, 0, SpringLayout.WEST, varLabel);
//			        layout.putConstraint(SpringLayout.EAST, attrPane, 0, SpringLayout.EAST, varXPanel);
//			        
			        layout.putConstraint(SpringLayout.NORTH, slidePanel, 7, SpringLayout.SOUTH, varLabel);
			        layout.putConstraint(SpringLayout.WEST,  slidePanel, 0, SpringLayout.WEST, varLabel);
			        layout.putConstraint(SpringLayout.EAST,  slidePanel, 0, SpringLayout.EAST, varXPanel);
			        layout.putConstraint(SpringLayout.SOUTH, slidePanel, 0, SpringLayout.SOUTH, varXPanel);
			        
		       
      		        
			        //Add new controls to current panel
			        varXPanel.add(varText);
			        varXPanel.add(varLabel);
			        varXPanel.add(slidePanel);
			        varXPanel.validate();			        
			        
			        //Add current panel to statically defined panel
			        variablesPanel.add(varXPanel);

			        //Validate panel again
			        variablesPanel.validate();
			        
		        }

		        //Add a listener for the get data button so we can process it
		        btnGetData.addActionListener(new btnGetDataListener());
		        constraintTextBox.setToolTipText("Example constraint expression format 'sst[0:1][34][108:132]'" );
		        //Create a horizontal separator
		        JSeparator horLine = new JSeparator();
		        horLine.setForeground(Color.BLACK);
		        horLine.setPreferredSize(new Dimension(variablesPanel.getWidth(), 5));
		        
		        //Add text box to input a constraint expression and a button to get data
		        SpringLayout frameLayout = (SpringLayout)frame.getContentPane().getLayout();
		        
		        //Add a horizontal line separator below the url textbox and button
		        frameLayout.putConstraint(SpringLayout.NORTH, horLine, 45, SpringLayout.SOUTH, urlTextBox);
		        
		        //Put the constraint textbox below the horizontal line
		        frameLayout.putConstraint(SpringLayout.NORTH, constraintLabel, 10, SpringLayout.SOUTH, horLine);
		        frameLayout.putConstraint(SpringLayout.NORTH, constraintTextBox, 0, SpringLayout.NORTH, constraintLabel);
		        frameLayout.putConstraint(SpringLayout.WEST, constraintTextBox, 5, SpringLayout.EAST, constraintLabel);
		        
		        //Add button to get data vertically aligned with the constraint text box and horizontally with the existing Check URL button
		        frameLayout.putConstraint(SpringLayout.NORTH, btnGetData, 0, SpringLayout.NORTH, constraintLabel);
		        frameLayout.putConstraint(SpringLayout.EAST, btnGetData, 0, SpringLayout.EAST, urlTextBox);
		        
		        frameLayout.putConstraint(SpringLayout.NORTH, variablesPanel, 10, SpringLayout.SOUTH, constraintTextBox);
		        
		        frame.getContentPane().add(horLine);
		        
		        frame.getContentPane().add(btnGetData);
		        frame.getContentPane().add(constraintLabel);
		        frame.getContentPane().add(constraintTextBox);
		        
		        
		        //Revalidate the frame so everything is rendered
		        frame.validate();
		        
			}
			catch(Throwable t)
			{
				t.printStackTrace(System.err);
				
	            String message = "Error occured, please check the url and try again.";
	            //Display error message to user
	            JOptionPane.showMessageDialog(new JFrame(), message, "Error",
	                    JOptionPane.ERROR_MESSAGE);
				
			}
			
		}
    	
    }


    /** Listen for GetData button click events
     * 
     * @author AJ
     * 
     */
        private class btnGetDataListener implements ActionListener
        {
        	
    		@Override
    		public void actionPerformed(ActionEvent evt) 
    		{
    			   			    			
    			String filename = JOptionPane.showInputDialog(new JFrame(), "Select Output File Name", "out.csv");
    			while(!filename.contains(".csv"))
    			{
    				JOptionPane.showMessageDialog(new JFrame(),  "Please enter a valid filename ending in .csv", "Invalid filename", JOptionPane.WARNING_MESSAGE);
    				filename = JOptionPane.showInputDialog(new JFrame(), "Select Output File Name", "out.csv");
    			}
    			
    			GridDataDap.GetData(urlTextBox.getText().trim(), constraintTextBox.getText().trim(), filename.trim());
    		}
        	
        }


}
